package tasks;

import Main.Parameters;
import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import plugin.Plugin;
import plugin.PluginLoader;
import system.MessageOUTPUT;

/**
 *
 * @author ZeM
 */
public class TaskDo {

    int[] SubTask;
    int priority;
    int NextSubTaskNumber;
    boolean FirstAttempt;
    static String adress_of_current_task;

    /**
     * Start doing task
     * @param adress_of_new_task the adress of task
     */
    public TaskDo(String adress_of_new_task) {
        adress_of_current_task = adress_of_new_task;
        FirstAttempt = true;
        int position_of_plugin = -1;//position of loaded plugin
        //loop of doing subtasks
        do {
            //get next subtask
            Next();
            //if next subtask has been found
            if (NextSubTaskNumber != -1) {

                //if Plugin mentioned in subtask exists
                if (new Plugin().Exists(Parameters.CurrentTaskPluginName)) {
                    //load plugin
                    //check if such plugin is already been loaded
                    boolean exists = false; //variable become true if plugin in loaded list has been found
                    int counter = 0; //counter for position in loaded list

                    //loop for finding plugin in loaded list; end if found or end of list
                    do {
                        //if found some plugin
                        if (Parameters.LoadedPluginNames[counter] != null) {
                            //if was found needed plugin
                            if (Parameters.LoadedPluginNames[counter].equals(Parameters.CurrentTaskPluginName)) {
                                exists = true; //meen that plugin already exists in loaded list
                                position_of_plugin = counter; //specifing position of found plugin
                                
                            }
                        }
                        //if plugin not found
                        if (!exists) {
                            //next position of counter;
                            counter++;
                        }
                    } while (!exists & counter < Parameters.LoadedPluginNames.length);
                    //if plugin hasn't been found in loaded plugin list
                    if (!exists) {

                        boolean find = false; //variable become true when find free space to load plugin
                        int count = 0; //counter for position in loaded list
                        do {
                            //if position in loaded plugin list is null
                            if (Parameters.LoadedPluginNames[count] == null) {
                                find = true;//find place to load


                            } else {
                                //add 1 to position
                                count++;
                            }
                        } while (!find & count < Parameters.LoadedPluginNames.length);

                        //load plugin

                        Parameters.LoadedPlugins[count]=new PluginLoader();
                        if (!Parameters.LoadedPlugins[count].Load(Parameters.CurrentTaskPluginName)) {
                            //cant load plugin
                            Parameters.TaskFailed = true;
                            NextSubTaskNumber = -1;
                            String[] mes = {"" + Parameters.CurrentTaskPluginName};
                            new MessageOUTPUT().OUTPUT("er0020", mes);

                        } else {
                            //successfully loaded
                            //input plugin name into loaded plugin list
                            Parameters.LoadedPluginNames[count]=Parameters.CurrentTaskPluginName;
                            position_of_plugin = count;  //specifing position of found plugin
                        }

                    }


                   //if loaded plugin need some parameters to start
                    if (Parameters.LoadedPlugins[position_of_plugin].HasParameters()) {
                        //if parameter names doesn't received
                        if (!Parameters.LoadedPlugins[position_of_plugin].GetParameters()) {
                            Parameters.TaskFailed = true; //task failed
                            NextSubTaskNumber = -1;
                            String[] mes = {Parameters.CurrentTaskPluginName};
                            new MessageOUTPUT().OUTPUT("er0011", mes);
                        }
                    }
                    //if task not failed
                    if (!Parameters.TaskFailed) {
                        //reading subtask information
                        if (ReadSubTask()) {

                            //input parameters into plugin
                            if(Parameters.LoadedPlugins[position_of_plugin].InputParameters(Parameters.Task_String_parameter, Parameters.Task_Group_String_parameter)){
                            //run plugin

                            if (Parameters.LoadedPlugins[position_of_plugin].Start()) { //start plugin

                                if (Parameters.LoadedPlugins[position_of_plugin].Crashed()) { //if plugin crashed while running
                                    Parameters.TaskFailed = true;
                                    NextSubTaskNumber = -1;
                                    //getting crash message
                                    String[] mes = {Parameters.CurrentTaskPluginName, new PluginLoader().CrashError()};
                                    new MessageOUTPUT().OUTPUT("er0015", mes);
                                } else {
                                    //meen that subtask successfully done
                                    SubTask[Parameters.CurrentTaskNumber] = 1;

                                }
                            } else {// if Start failed
                                Parameters.TaskFailed = true;
                                NextSubTaskNumber = -1;
                            }

                        }else {
                        //can't input parameters into plugin

                        }

                        } else { //if can't read subtask
                            Parameters.TaskFailed = true;
                            NextSubTaskNumber = -1;
                            String[] mes = {Parameters.TaskName[Parameters.CurrentTaskNumber], "" + NextSubTaskNumber};
                            new MessageOUTPUT().OUTPUT("er0012", mes);

                        }

                    }

                } else {//if plugin doesn't exists
                    Parameters.TaskFailed = true;
                    NextSubTaskNumber = -1;
                    String[] mes = {Parameters.TaskName[Parameters.CurrentTaskNumber], "" + NextSubTaskNumber, "" + Parameters.CurrentTaskPluginName};
                    new MessageOUTPUT().OUTPUT("er0009", mes);

                }




            }
            new Plugin().NullParameters(); //null all task parameters
        } while (NextSubTaskNumber != -1);


    }

    /**
     * Getting next subtask
     * @param adress_of_current_task adress of current task
     */
    void Next() {

        //checking tasks
        try {
            DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
            Document doc = docBuilder.parse(new File(adress_of_current_task));

            // normalize text representation
            doc.getDocumentElement().normalize();
            //getting tasks
            NodeList listOfTasks = doc.getElementsByTagName("task");
            int totalTasks = listOfTasks.getLength();

            if (FirstAttempt) { //if only start
                SubTask = new int[totalTasks];
                for (int i = 0; i < totalTasks; i++) {
                    SubTask[i] = 0;
                }
                FirstAttempt = false;
            }

            NextSubTaskNumber = -1;
            //loop of finding next task;
            for (int j = 0; j < totalTasks; j++) {
                if (SubTask[j] == 0) {


                    Node firstNode = listOfTasks.item(j);
                    if (firstNode.getNodeType() == Node.ELEMENT_NODE) {


                        Element firstElement = (Element) firstNode;

                        boolean flag = true; //mean that everithing is OK

                        //----description
                        NodeList nodelist = firstElement.getElementsByTagName("priority");
                        int length = nodelist.getLength();
                        if (length > 0) {
                            Element nelement = (Element) nodelist.item(0);

                            NodeList textList = nelement.getChildNodes();
                            int pr = Integer.parseInt(((Node) textList.item(0)).getNodeValue().trim());
                            if (NextSubTaskNumber < 0) {
                                NextSubTaskNumber = j;
                                priority = pr;
                            } else if (pr > priority) {
                                NextSubTaskNumber = j;
                                priority = pr;
                            }
                        } else {//priority field has not been specified
                            if (NextSubTaskNumber < 0) {
                                NextSubTaskNumber = j;
                                priority = Parameters.DefaultSubtaskPriority;
                            } else if (Parameters.DefaultSubtaskPriority > priority) {
                                NextSubTaskNumber = j;
                                priority = Parameters.DefaultSubtaskPriority;
                            }
                        }

                    }

                }
            }

            //getting parameters
            if (NextSubTaskNumber > -1) {



                Node firstPersonNode = listOfTasks.item(NextSubTaskNumber);
                if (firstPersonNode.getNodeType() == Node.ELEMENT_NODE) {


                    Element firstElement = (Element) firstPersonNode;
                    //getting name of plugin to run
                    NodeList nodelist = firstElement.getElementsByTagName("description");
                    int length = nodelist.getLength();
                    String plugin_name = null;
                    if (length > 0) {
                        Element nelement = (Element) nodelist.item(0);

                        NodeList textList = nelement.getChildNodes();
                        plugin_name = ((Node) textList.item(0)).getNodeValue().trim();
                    } else {
                        Parameters.TaskFailed = true;
                        NextSubTaskNumber = -1;
                        String[] mes = {Parameters.TaskName[Parameters.CurrentTaskNumber], "" + NextSubTaskNumber};
                        new MessageOUTPUT().OUTPUT("er0010", mes);

                    }
                    if (!Parameters.TaskFailed) {
                        //SETTING CURRENT PLUGIN NAME
                        Parameters.CurrentTaskPluginName = plugin_name;


                    }
                }



            }
        } catch (Exception er) {
        }
    }

    /**
     * Read sub task information
     * @return true if successfull
     */
    private boolean ReadSubTask() {
        try {

            DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
            Document doc = docBuilder.parse(new File(adress_of_current_task));
            // normalize text representation
            doc.getDocumentElement().normalize();
            //getting tasks
            NodeList listOfTasks = doc.getElementsByTagName("task");
            int totalTasks = listOfTasks.getLength();

            Node firstNode = listOfTasks.item(NextSubTaskNumber);
            if (firstNode.getNodeType() == Node.ELEMENT_NODE) {

                Element firstElement = (Element) firstNode;
                //reading parameters:
                if (Parameters.Plugin_parameter_name != null) {
                    Parameters.Task_String_parameter = new String[Parameters.Plugin_parameter_name.length][];
                    //loop for finding all parameters

                    for (int k = 0; k < Parameters.Plugin_parameter_name.length; k++) {

                        if (Parameters.Plugin_parameter_name[k] != null) { //if parameter k exists
                            //getting all elements by parameter name
                            NodeList nodelist = firstElement.getElementsByTagName(Parameters.Plugin_parameter_name[k]);
                            //specifing array size
                            Parameters.Task_String_parameter[k] = new String[nodelist.getLength()];
                            //geting all parameters values
                            for (int p = 0; p < nodelist.getLength(); p++) {
                                Element nelement = (Element) nodelist.item(p);
                                NodeList textList = nelement.getChildNodes();
                                Parameters.Task_String_parameter[k][p] = ((Node) textList.item(0)).getNodeValue().trim();
                            }

                        }

                    }
                }
                //reading groups
                if (Parameters.Plugin_group_parameter_name != null) {
                    Parameters.Task_Group_String_parameter = new String[Parameters.Plugin_group_name.length][][][];
                    for (int k = 0; k < Parameters.Plugin_group_name.length; k++) {
                        if (Parameters.Plugin_group_name[k] != null) {//if group k exists
                            //getting all groups by group name
                            NodeList nodelist = firstElement.getElementsByTagName(Parameters.Plugin_group_name[k]);


                            //specifing array size
                            Parameters.Task_Group_String_parameter[k] = new String[nodelist.getLength()][Parameters.Plugin_group_parameter_name[k].length][];
                            //loop for all groups
                             
                            for (int p = 0; p < nodelist.getLength(); p++) {
                                //getting group parameters
                         
                                Node node = nodelist.item(p);
                                if (node.getNodeType() == Node.ELEMENT_NODE) {
                                   
                                    Element element = (Element) node;
                                    //getting parameters
                                    for (int f = 0; f < Parameters.Plugin_group_parameter_name[k].length; f++) {
                             
                                        if (Parameters.Plugin_group_parameter_name[k][f] != null) { //if parameter f in group k exists
                                            //getting all parameters by group parameter name
                                            
                                            NodeList ndlist = element.getElementsByTagName(Parameters.Plugin_group_parameter_name[k][f]);
                                            //specifing array size
                                            
                                            Parameters.Task_Group_String_parameter[k][p][f] = new String[ndlist.getLength()];
                                            //geting values of all parameters
                                            for (int z = 0; z < ndlist.getLength(); z++) {
                                                
                                                Element nelement = (Element) ndlist.item(z);
                                               
                                                if(nelement.hasChildNodes()){
                                                NodeList textList = nelement.getChildNodes();
                                                
                                                Parameters.Task_Group_String_parameter[k][p][f][z] = ((Node) textList.item(0)).getNodeValue().trim();
                                                
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }

                    }
                }

            }

        } catch (Exception error) {
            System.err.println(error+ " ReadSubTask");
            return false;
        }
        return true;
    }
}
